package com.panopset.refactorsf;

import java.awt.LayoutManager;

import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;

import com.panopset.sf.FontManager;
import com.panopset.sf.Windoc;

/**
 * Pan field.
 *
 * Fields should do the following:
 * <ul>
 * <li>
 * Have static access to font, color, other attributes that will be common to an
 * application.</li>
 * <li>
 * Persist with a document, or application.</li>
 * <li>
 * Allow for validation. (text, number, file, directory).</li>
 * </ul>
 *
 * @author Karl Dinwiddie
 *
 * @param <T>
 *            T extends JComponent.
 */
public abstract class PanField<T extends JComponent> extends PanNoBorderField<T> {

    /**
     * Layout.
     */
    private LayoutManager playout;

    public PanField(final Windoc wd, final String borderTitle, final String toolTipText,
            final String defaultValue, final String key) {
        super(wd, defaultValue, toolTipText, key);
        pborderTitle = borderTitle;
    }

    public PanField(final Windoc wd, final String borderTitle, final String toolTipText,
            final String defaultValue) {
        super(wd, defaultValue, toolTipText, "");
        pborderTitle = borderTitle;
    }


    /**
     * @return Layout.
     */
    protected abstract LayoutManager createLayout();


    /**
     * Border title.
     */
    private String pborderTitle;

    /**
     * @return Border title.
     */
    public final String getBorderTitle() {
        if (pborderTitle == null) {
            pborderTitle = "";
        }
        return pborderTitle;
    }

    /**
     * Normal border.
     */
    private TitledBorder normalBorder;
    /**
     * Wait border.
     */
    private TitledBorder waitBorder;
    /**
     * Alert border.
     */
    private TitledBorder alertBorder;
    /**
     * In progress border.
     */
    private TitledBorder inprogressBorder;

    /**
     * Set border title.
     *
     * @param newBorderTitle
     *            New border title.
     */
    public final void setBorderTitle(final String newBorderTitle) {
        pborderTitle = newBorderTitle;
        getNormalBorder().setTitle(pborderTitle);
        getWaitBorder().setTitle(pborderTitle);
        getAlertBorder().setTitle(pborderTitle);
        getInprogressBorder().setTitle(pborderTitle);
    }


    /**
     * @return Normal titled border.
     */
    protected final TitledBorder getNormalBorder() {
        if (isWaitingForInput()) {
            return getAlertBorder();
        }
        if (normalBorder == null) {
            LineBorder lb = new LineBorder(
                    LookAndFeel.Colors.BORDER_COLOR_NORMAL.getColor(), 1);
            normalBorder = new TitledBorder(lb, pborderTitle);
            FontManager.getInstance().register(normalBorder, FontManager.FontType.borderTitle);
            normalBorder.setTitleColor(LookAndFeel.Colors.BORDER_COLOR_NORMAL
                    .getColor());
        }
        return normalBorder;
    }

    /**
     * @return Wait titled border.
     */
    protected final TitledBorder getWaitBorder() {
        if (waitBorder == null) {
            LineBorder lb = new LineBorder(LookAndFeel.Colors.BORDER_COLOR_WAIT
                    .getColor(), 1);
            waitBorder = new TitledBorder(lb, pborderTitle);
            waitBorder.setTitleColor(LookAndFeel.Colors.BORDER_COLOR_WAIT
                    .getColor());
            FontManager.getInstance().register(waitBorder, FontManager.FontType.borderTitle);
        }
        return waitBorder;
    }

    /**
     * @return Alert titled border.
     */
    protected final TitledBorder getAlertBorder() {
        if (alertBorder == null) {
            LineBorder lb = new LineBorder(
                    LookAndFeel.Colors.BORDER_COLOR_ALERT.getColor(), 1);
            alertBorder = new TitledBorder(lb, pborderTitle);
            alertBorder.setTitleColor(LookAndFeel.Colors.BORDER_COLOR_ALERT
                    .getColor());
            FontManager.getInstance().register(alertBorder, FontManager.FontType.borderTitle);
            setNormalHighlighting();
        }
        return alertBorder;
    }

    /**
     * @return In progress titled border.
     */
    protected final TitledBorder getInprogressBorder() {
        if (inprogressBorder == null) {
            LineBorder lb = new LineBorder(
                    LookAndFeel.Colors.BORDER_COLOR_INPROGRESS.getColor(), 1);
            inprogressBorder = new TitledBorder(lb, pborderTitle);
            inprogressBorder
                    .setTitleColor(LookAndFeel.Colors.BORDER_COLOR_INPROGRESS
                            .getColor());
            FontManager.getInstance().register(inprogressBorder,
                    FontManager.FontType.borderTitle);
            setNormalHighlighting();
        }
        return inprogressBorder;
    }

    /**
     * Set normal highlighting for the boder title.
     */
    public final void setNormalHighlighting() {
        if (pborderTitle == null) {
            return;
        }
        getPanel().setBorder(getNormalBorder());
        reset();
    }

    /**
     * If you want to show something in progress, use this.
     */
    public final void setWaitHighlighting() {
        if (pborderTitle == null) {
            return;
        }
        getPanel().setBorder(getWaitBorder());
        reset();
    }

    /**
     * Set alert highlighting.
     */
    public final void setAlertHighlighting() {
        if (pborderTitle == null) {
            return;
        }
        getPanel().setBorder(getAlertBorder());
        reset();
    }

    /**
     * Set in progress highlighting.
     */
    public final void setInprogressHighlighting() {
        if (pborderTitle == null) {
            return;
        }
        getPanel().setBorder(getInprogressBorder());
        reset();
    }

    /**
     * Reset.
     */
    public final void reset() {
        getPanel().invalidate();
    }


    /**
     * Check to see if we need to alert the user for input action.
     */
    protected void checkInput() {
    }

    /**
     * Is waiting for input.
     */
    private boolean isWaitingForInput = false;

    /**
     * @return True if waiting for input.
     */
    private boolean isWaitingForInput() {
        checkInput();
        return isWaitingForInput;
    }

    /**
     * @param value
     *            Value to set.
     */
    public final void setWaitingForInput(final boolean value) {
        isWaitingForInput = value;
    }


    /**
     * @return Layout.
     */
    final LayoutManager getLayout() {
        if (playout == null) {
            playout = createLayout();
        }
        return playout;
    }

    /**
     * Containing panel.
     */
    private TPanel panel;

    /**
     * @return Containing panel.
     */
    public final JPanel getPanel() {
        if (panel == null) {
            panel = new TPanel.Builder().layout(getLayout()).construct();
            panel.setBackground(LookAndFeel.Colors.BG_COLOR.getColor());
            panel.setToolTipText(ptoolTipText);
            panel.add(getInnerComponent());
            setNormalHighlighting();
        }
        return panel;
    }
}
